www.gusucode.com > php框架系统:MDPHP麦迪源码 v1.xPHP源码程序 > php框架系统:MDPHP麦迪源码 v1.x/mdphp_v1.0.beta/mdphp_v1.0.beta/Library/Model/public.php

    <?php

	/**
	 * 麦迪模型类
	 * @author: 麦迪科技 <i@md8.cc>
	 * @link: http://soft.md8.cc
	 * @version: 1.3
	 */

	namespace MDPHP;

	import('$->Library->Model->Db->interface');

	final class Model{

		public $name, $connection, $opt, $data;
		private $obj;

		/**
		 * 模型实例化
		 * @param	string	$name		表名
		 * @param	array	$connection	模型配置项
		 */
		public function __construct($name=null, $connection){

			//初始化驱动
			$driver = strtolower($connection['TYPE']);
			$className = 'MDPHP\Db' . ucfirst($driver);
			import('$->Library->Model->Db->' . $driver);

			//建立驱动对象
			$this->obj = new $className($connection);

			//错误处理
			if(is_array($this->obj->error)) error($this->obj->error['id'], $this->obj->error['title'], $this->obj->error['content']);

			//初始类成员属性
			$this->connection = $connection;
			$this->opt = array(
				'pri'		=>	null,			//主键
				'field'		=>	'*',			//查询键组
				'fieldData'	=>	array(),		//字段组
				'where'		=>	'',
				'group'		=>	'',
				'having'	=>	'',
				'order'		=>	'',
				'limit'		=>	'',
				'join'		=>	''
			);

			//设置当前表
			$this->table($name);

		}

		/**
		 * 执行SQL
		 * @param	string	$sql
		 * @return	[type]			成功返回资源标识符, 失败返回False.
		 */
		public function query($sql){
			$result = $this->obj->query($sql);
			Custom::log(array('sql'=>$sql, 'result'=>($result ? 'True' : 'False')), 'Q');
			return $result;
		}

		/**
		 * 设置查询条件
		 * @param	[type]	$opt	条件(可为字符串、数组)
		 * @return	Model类
		 *
		 * -- 以下测试表索引为`id` --
		 *
		 * 索引查询: where(1)
		 * 	`id`=1
		 * 多索引查询(OR): where(array(1, 2, 3, 4, 5))
		 * 	`id`=1 and `id`=2 and `id`=3 and `id`=4 and `id`=5
		 *
		 * 键名查询: where(array('name'=>'xhao'))
		 * 	`name`="xhao"
		 * 键名+条件: where(array('name'=>array('xhao', 'sxyz', array('or'))))
		 * 	`name`="xhao" or `name`="sxyz"
		 * 键名+条件: where(array('name'=>array('xhao', 'sxyz', array('!=', 'and'))))
		 * 	`name`<>"xhao" and `name`<>"sxyz"
		 *
		 * 数组展开: where(array('id'=>array(1, 2, array(3, 4), 5, array('<>'))))
		 * 	`id`<>1 or `id`<>2 or `id`<>3 or `id`<>4 or `id`<>5
		 *
		 * In: where(array('id'=>array(array(1, 2, 3, 4), 5, 6, array('in'))))
		 * 	`id` in (1,2,3,4,5,6)
		 * Not in: where(array('id'=>array(array(1, 2, 3, 4), 5, 6, array('not in'))))
		 * 	`id` not in (1,2,3,4,5,6)
		 * Between: where(array('id'=>array(1, 100, array('between'))))
		 * 	`id` between 1 and 100
		 * Not between: where(array('id'=>array(1, 100, array('not between'))))
		 * 	`id` not between 1 and 100
		 * Like: where(array('name'=>array('xhao', array('like'))))
		 * 	`name` like "xhao"
		 * Not like: where(array('name'=>array('xhao', array('not like'))))
		 * 	`name` not like "xhao"
		 *
		 * Or: where(array('name'=>array('xhao', 'sxyz', array('<>', 'or'))))
		 * 	`name`<>"xhao" or `name`<>"sxyz"
		 * And: where(array('name'=>array('xhao', 'sxyz', array('<>', 'and'))))
		 * 	`name`<>"xhao" and `name`<>"sxyz"
		 *
		 */
		public function where($opt, $logic='and'){

			//初始化
			$where = '';
			$this->opt['where'] = '';

			if(is_numeric($opt)){

				//主键方式
				$where = $this->opt['pri'] . '=' . $opt;

			}elseif(is_string($opt)){

				//SQL查询
				$where = $opt;

			}elseif(is_object($opt)){

				//转换为数组
				$opt = get_object_vars($opt);

			}


			if(is_array($opt)){

				//查询语句
				list($sentence[0], $sentence[1]) = array(
					array('IN', 'OR', 'AND', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'LIKE', 'NOT LIKE'),
					array('=', '>', '<', '<>', '==', '!=')
				);

				//多主键模式
				foreach($opt as $key => $value){
					if(is_numeric($key) && is_numeric($value)){
						$where .= $this->opt['pri'] . '=' . $value . ' ' . $logic . ' ';
					}else{
						$where = ''; break;
					}
				}
				if($where) goto end;

				//遍历循环
				foreach($opt as $key => $value){

					//解析键名
					$key = self::parseField($key);

					//多字段
					if(is_array($value)){

						//高级配置
						if(isset($value[count($value)-1]) && is_array(end($value))){
							$adv = end($value);
							if(count($adv)>0 && (in_array_case($adv[0], $sentence[0]) || in_array($adv[0], $sentence[1])))
								array_pop($value);
							else
								unset($adv);
						}

						//符号
						$sign = in_array($adv[0], $sentence[1]) ? str_replace(array('==', '!='), array('=', '<>'), $adv[0]) : '=';

						//类型
						$type = (isset($adv)) ? trim(strtolower(end($adv))) : 'and';

						//展开数组
						foreach($value as $k => $v){
							if(is_array($v))
								array_splice($value, $k, 1, array_values($v));
						}

						//IN - NOT IN
						if(in_array($type, array('in', 'not in'))){
							$where .= $key . ' ' . $type . ' (' . implode(',', array_map(function($v){
								return $this->obj->escapeString($v);
							}, $value)) . ')';
						}

						//BETWEEN - NOT BETWEEN
						if(in_array($type, array('between', 'not between'))){
							$where .= $key . ' ' . $type . ' ' . $this->obj->escapeString(isset($value[0]) ? $value[0] : '') . ' ' . $logic . ' ' . $this->obj->escapeString(isset($value[1]) ? $value[1] : '');
						}

						//LIKE - NOT LIKE
						if(in_array($type, array('like', 'not like'))){
							$where .= $key . ' ' . $type . ' ' . $this->obj->escapeString(isset($value[0]) ? $value[0] : '');
						}

						//AND - OR
						if(in_array($type, array('and', 'or'))){
							foreach($value as $value){
								$where .= $key . $sign . $this->obj->escapeString($value) . ' ' . $type . ' ';
							}
							$where = trim_right($where, ' ' . $type . ' ');
						}

						$where .= ' ' . $logic . ' ';

					}else{

						//普通模式
						$where .= $key . '=' . $this->obj->escapeString($value) . ' ' . $logic . ' ';

					}

				}
		
			}

		end:
			$this->opt['where'] = preg_replace('/^\s*(or|and|xor)\s*/i', '', $where);					//首部清理
			$this->opt['where'] = preg_replace('/\s*(or|and|xor)\s*$/i', '', $this->opt['where']);		//尾部清理
			$this->opt['where'] = ' where ' . $this->opt['where'];
			return $this;

		}

		/**
		 * 设置查询字段
		 * @param	string	$rule	预设值的字段(可为字符串、数组 为字符串时以","分割 字段不加"`")
		 * @param	string	$auto	自动补全前缀
		 * @return	Model类
		 *
		 *	设置别名:
		 *		field('article.*,class.id as classID', true)
		 *		field(array('article.*', 'class.id as classID'), true)
		 *
		 */
		public function field($rule='*', $auto=false){
			if(!is_array($rule))
				$rule = explode(',', $rule);
			$str = null;
			foreach($rule as $key => $value){
				$value = str_replace(' AS ', ' as ', $value);
				if(strpos($value, ' as ')===false){
					$value = self::parseField(($auto ? $this->connection['PREFIX'] : '') . $value);
				}else{
					$array = explode(' as ', $value);
					$value = self::parseField(($auto ? $this->connection['PREFIX'] : '') . $array[0]) . ' as ' . self::parseField($array[1]);
				}

				$str .= $value . ',';
			}
			$this->opt['field'] = rtrim($str, ',');
			return $this;
		}

		/**
		 * 设置排序
		 * @param	string	$name	字段名
		 * @param	string	$by		排序方式: asc 或 desc
		 * @return	Model类
		 */
		public function order($name, $by='asc'){
			$this->opt['order'] = ' order by ' . ($name ? self::parseField($name).' ' : '') . $by;
			return $this;
		}

		/**
		 * 设置截取
		 * 		2个参数全填写:	参数1为开始位置(从0开始), 参数2为截取数量(<1 则使用1);
		 * 		只填写参数1:	限制数量(可用于删除表项), <1则使用1填充;
		 * @param	integer	$param1	参数1
		 * @param	integer	$param2	参数2
		 * @return	Model类
		 */
		public function limit($param1=0, $param2=1){
			if(func_num_args() > 1)
				$this->opt['limit'] = ' limit ' . intval($param1) . ',' . intval($param2<1 ? 1 : $param2);
			else
				$this->opt['limit'] = ' limit ' . intval($param1<1 ? 1 : $param1);
			return $this;
		}

		/**
		 * 列出一条记录
		 * @return	array
		 */
		public function find(){
			if(!$this->obj->result)
				$this->query('select ' . $this->opt['field'] . ' from ' . ($this->opt['join'] ? $this->opt['join'] : self::parseField($this->name)) . $this->opt['where'] . $this->opt['order'] . $this->opt['limit']);
			return $this->obj->fetch();
		}

		/**
		 * 列出所有记录
		 * @return	array
		 */
		public function select(){
			if(!$this->obj->result)
				$this->query('select ' . $this->opt['field'] . ' from ' . ($this->opt['join'] ? $this->opt['join'] : self::parseField($this->name)) . $this->opt['where'] . $this->opt['order'] . $this->opt['limit']);
			$array = array();
			while($row = $this->obj->fetch(false)){
				$array[] = $row;
			}
			$this->obj->fetch();	//回收
			return $array;
		}

		/**
		 * 统计表项数量
		 * @param	string	$field	表名, 为空则使用field()方法所设置值
		 * @return	integer			表项数量
		 */
		public function count($field=null){
			if($field === null) $field = $this->opt['field'];
			$this->query('select count(' . $field . ') as `MDPHP` from ' . ($this->opt['join'] ? $this->opt['join'] : self::parseField($this->name)) . $this->opt['where']);
			$result = $this->find();
			return is_array($result) ? $result['MDPHP'] : $result;
		}

		/**
		 * 欲提交数据设置
		 * @param	array	$data	被设置的数据, 为空使用POST数据.
		 * @return	Model类
		 */
		public function data($data=null){
			if(empty($data))
				$data = $_POST;
			if(get_magic_quotes_gpc()){
				foreach($data as $key => $value){
					$data[$key] = stripslashes($value);
				}
			}
			$this->data = $data;
			return $this;
		}

		/**
		 * 添加表项
		 * @param	array	$data	可为空, 为空则使用data()方法所设置数据.
		 * @return	[type]			添加失败返回False, 成功返回主键ID(如无主键则返回0).
		 */
		public function add($data=null){
			if(!empty($data))
				$this->data($data);
			$keys = null; $values = null;
			foreach($this->data as $k => $v){
				$keys .= self::parseField($k) . ',';
				$values .= $this->obj->escapeString($v) . ',';
			}
			$this->optInit();
			if($this->query('insert into ' . self::parseField($this->name) . '(' . rtrim($keys, ',') . ') values (' . rtrim($values, ',') . ')'))
				return $this->obj->getInsertId();
			else
				return false;
		}

		/**
		 * 修改表项
		 * @param	array	$data	可为空, 为空则使用data()方法所设置数据.
		 * @param	integer	$pri	可空, 若提供主键, 则被优先使用.
		 * @return	[type]			执行失败返回False, 成功返回修改行数.
		 */
		public function save($data=null, $pri=0){
			if(!empty($data))
				$this->data($data);
			if($pri && func_num_args()>1)
				$where = ' where ' . $this->opt['pri'] . '=' . intval($pri);
			else
				$where = $this->opt['where'];
			$str = null;
			foreach($this->data as $key => $value){
				$str .= self::parseField($key) . '=' . $this->obj->escapeString($value) . ',';
			}
			$this->query('update ' . self::parseField($this->name) . ' set ' . rtrim($str, ',') . $where . $this->opt['order'] . $this->opt['limit']);
			$this->optInit();
			if($this->obj->result)
				return $this->obj->getAffectedRows();
			else
				return false;
		}

		/**
		 * 删除表项
		 * @param	integer	$pri	可空, 若提供主键, 则被优先使用.
		 * @return	[type]			执行失败返回False, 成功返回删除行数.
		 */
		public function del($pri=0){
			if($pri && func_num_args()>0)
				$where = ' where ' . $this->opt['pri'] . '=' . intval($pri);
			else
				$where = $this->opt['where'];
			$this->query('delete from ' . ($this->opt['join'] ? $this->opt['join'] : self::parseField($this->name)) . $where . $this->opt['order'] . $this->opt['limit']);
			if($this->obj->result)
				return $this->obj->getAffectedRows();
			else
				return false;
		}

		/**
		 * 关联查询
		 * @param	string	$left	左表, 为空删除关联
		 * @param	string	$right	右表
		 * @param	string	$where	条件语句
		 * @param	string	$type	关联类型
		 * @return	Model类
		 *
		 *	join('article', 'class', array('article.class'=>'class.id'))
		 *		`md_article` inner join `md_class` on `md_article`.`class`=`md_class`.`id`
		 *
		 */
		public function join($left='', $right='', $where, $type='inner join'){
			if(func_num_args()<2 && !$left) $this->opt['join'] = '';
			if(is_array($where)){
				$str = '';
				foreach($where as $key => $value){
					$str .= self::parseField($this->connection['PREFIX'].$key) . '=' . self::parseField($this->connection['PREFIX'].$value) . ' and ';
				}
				$str = trim_right($str, ' and ');
			}else{
				$str = $where;
			}
			$this->opt['join'] = self::parseField($this->connection['PREFIX'].$left) . ' ' . $type . ' ' . self::parseField($this->connection['PREFIX'].$right) . ' on ' . $str;
			return $this;
		}

		/**
		 * 设置表
		 * @param	string	$name
		 * @return	Model类
		 */
		public function table($name){
			$this->name = $this->connection['PREFIX'] . $name;

			//设置类成员属性
			$this->getAllField();
			$this->getPrimaryKey();

			return $this;
		}

		/**
		 * 获取数据表结构并缓存
		 * @return array
		 */
		public function getAllField(){
			$this->query('show columns from ' . self::parseField($this->name));
			$result = $this->select();
			foreach($result as $value){
				$fieldData = array();
				$fieldData['field'] = $value['Field'];
				$fieldData['type'] = $value['Type'];
				$fieldData['null'] = $value['Null'];
				$fieldData['key'] = strtoupper($value['Key']) == 'PRI';
				$fieldData['default'] = $value['Default'];
				$fieldData['extra'] = $value['Extra'];
				$this->opt['fieldData'][$fieldData['field']] = $fieldData;
			}
		}

		/**
		 * 获得表主键字段
		 * @return	string	字段名
		 */
		public function getPrimaryKey(){
			foreach($this->opt['fieldData'] as $value){
				if($value['key']){
					$this->opt['pri'] = self::parseField($value['field']);
					break;
				}
			}
		}

		/**
		 * 字段代码解析
		 * @param	string	$str
		 * @return	string			处理后代码
		 */
		static function parseField($str){
			$array=explode('.', $str); $str='';
			foreach($array as $value){
				$str .= ($value=='*' ? '*' : ('`'.str_replace('`', '\`', trim($value)).'`.'));
			}
			return rtrim($str, '.');
		}

		/**
		 * 配置信息还原
		 */
		private function optInit($opt=false){
			if($opt){
				$this->opt = array(
					'field'		=>	'*',
					'where'		=>	'',
					'group'		=>	'',
					'having'	=>	'',
					'order'		=>	'',
					'limit'		=>	'',
					'join'		=>	''
				);
			}
			$this->data = null;
			return $this;
		}

	}